
import { format } from '@/filters/date';
import * as formulajs from '@formulajs/formulajs/lib/esm/index.mjs';
import math from '@/utils/math';
import { DATEFUN, FINANCIAL, ENGINEERING, LOGICAL, MATH, STATISTICAL, TEXTFUN } from './allFunction';

export const functionList = [
  {
    name: '数学函数',
    children: [
      {
        name: 'SUM',
        summary: `SUM函数可以获取一组数值的总和
        用法：SUM(数字1,数字2,...)
        示例：SUM(语文成绩,数学成绩, 英语成绩)返回三门课程的总分`
      }, {
        name: 'ABS',
        summary: `ABS函数可以获取一个数的绝对值
        用法：ABS(数字)
        示例：ABS(-8)可以返回8，也就是-8的绝对值`
      }, {
        name: 'AVERAGE',
        summary: `AVERAGE函数可以获取一组数值的算术平均值
        用法：AVERAGE(数字1,数字2,...)
        示例：AVERAGE(语文成绩,数学成绩, 英语成绩)返回三门课程的平均分`
      }, {
        name: 'COUNTA',
        summary: `COUNTA函数可以获取参数的数量
        用法：COUNTA(值,值,...)
        示例：COUNTA(小明,小王,小张,小李)返回4，也就是人员的数量`
      }, {
        name: 'COUNTIF',
        summary: `COUNTIF函数可以获取数组中满足条件的参数个数
        用法：COUNTIF(数组,"条件")
        示例：COUNTIF(子表单.性别, "女")，可得到子表单中性别填的是"女"的数据条数；COUNTIF([1,2,3,4],">2")，可得到1,2,3,4中大于2的数字数量，结果为2。`
      }, {
        name: 'LARGE',
        summary: `LARGE函数可以获取数据集中第k个最大值
        用法：LARGE(数组,k)
        示例：LARGE(学生成绩.数学成绩,1)返回子表单"学生成绩"中排名第1的"数学成绩"`
      }, {
        name: 'SMALL',
        summary: `SMALL函数可以返回数据集中第k个最小值
        用法：SMALL(数组,k)
        示例：SMALL(学生成绩.数学成绩, 1)返回子表单"学生成绩"中排名倒数第一的"数学成绩"`
      }, {
        name: 'MAX',
        summary: `MAX函数可以获取一组数值的最大值
        用法：MAX(数字1,数字2,...)
        示例：MAX(语文成绩,数学成绩,英语成绩)返回三门课程中的最高分`
      }, {
        name: 'MIN',
        summary: `MIN函数可以获取一组数值的最小值
        用法：MIN(数字1,数字2,...)
        示例：MIN(语文成绩,数学成绩,英语成绩)返回三门课程中的最低分`
      }, {
        name: 'MOD',
        summary: `MOD函数可以获取两数相除的余数
        用法：MOD(被除数,除数)
        示例：MOD(11,2)返回1，也就是11/2的余数`
      }, {
        name: 'ROUND',
        summary: `ROUND函数可以对数值进行四舍五入
        用法：ROUND(数值,精确位数)
        示例：ROUND(3.1415926, 2)返回3.14`
      },
      ...MATH
    ]
  },
  {
    name: '文本函数',
    children: [
      {
        name: 'CONCATENATE',
        summary: `CONCATENATE函数可以将多个文本合并成一个文本
        用法：CONCATENATE(文本1,文本2,...)
        示例：CONCATENATE("三年二班","周杰伦")会返回"三年二班周杰伦"`
      },
      {
        name: 'RMBCAP',
        summary: `RMBCAP函数可以将金额小写转换为人民币大写金额形式
        用法：RMBCAP(数字)
        示例：RMBCAP(12.23)返回 壹拾贰元贰角叁分`
      },
      {
        name: 'TRIM',
        summary: `TRIM函数可以删除文本首尾的空格
        用法：TRIM(文本)
        示例：TRIM(" 飞博共创 ")返回"飞博共创"`
      },
      {
        name: 'UNION',
        summary: `UNION函数合并多个文本数组，重复文本只显示一次
        用法：UNION(文本1，文本2，文本3，文本4)或UNION([数组])
        示例：UNION("张三","李四","王五","张三","李四")返回值为["张三","李四","王五"]`
      },
      {
        name: 'VALUE',
        summary: `VALUE函数可以将文本转化为数字
        用法：VALUE(文本)
        示例：VALUE("3.1415")返回3.1415`
      },
      {
        name: 'TEXT',
        summary: `TEXT函数可以将数字转化成文本
        用法：TEXT(数字)
        示例：TEXT(3.1415)返回"3.1415"`
      },
      {
        name: 'EXACT',
        summary: `EXACT函数可以比较两个文本是否完全相同，完全相同则返回true，否则返回false
        用法：EXACT(文本1, 文本2)
        示例：EXACT(手机号,中奖手机号)，如果两者相同，返回true，如果不相同，返回false`
      },
      {
        name: 'LOWER',
        summary: `LOWER函数可以将一个文本中的所有大写字母转换为小写字母
        用法：LOWER(文本)
        示例：LOWER("JAYZ")返回"jayz"`
      },
      {
        name: 'UPPER',
        summary: `UPPER函数可以将一个文本中的所有小写字母转换为大写字母
        用法：UPPER(文本)
        示例：UPPER("jayz")返回"JAYZ"`
      }, {
        name: 'REPT',
        summary: `REPT函数可以将文本重复一定次数
        用法：REPT(文本,重复次数)
        示例：REPT("文本",3)返回"文本文本文本"`
      }, {
        name: 'LEFT',
        summary: `LEFT函数可以从一个文本的第一个字符开始返回指定个数的字符
        用法：LEFT(文本,文本长度)
        示例：LEFT("三年二班周杰伦",2)返回"三年"，也就是"三年二班周杰伦"的从左往右的前2个字符`
      }, {
        name: 'RIGHT',
        summary: `RIGHT函数可以获取由给定文本右端指定数量的字符构成的文本值
        用法：RIGHT(文本,文本长度)
        示例：RIGHT("三年二班周杰伦",3)返回"周杰伦"，也就是"三年二班周杰伦"从右往左的前3个字符`
      },
      ...TEXTFUN
    ]
  },
  {
    name: '日期函数',
    children: [
      {
        name: 'DATEDIF',
        summary: `DATEDIF函数可以计算两个日期时间相差的年数、月数、天数、小时数、分钟数、秒数。
        用法：DATEDIF(开始时间,结束时间,[单位])，单位可以是 "y" 、"M"、"d"、"h"、"m"、"s"
        示例：DATEDIF(下单时间,付款时间,"h")，如果下单时间是9:00，付款时间为当天10:30，计算得到的小时差为1.5。`
      }, {
        name: 'DATEDELTA',
        summary: `DATEDELTA函数可以将指定日期加/减指定天数
        用法：DATEDELTA(指定日期,需要加减的天数)
        示例：略`
      }, {
        name: 'DAYS',
        summary: `DAYS函数可以返回两个日期之间相差的天数。
        用法：DAYS(结束日期,开始日期)
        示例：略`
      },
      ...DATEFUN
    ]
  },
  {
    name: '逻辑函数',
    children: [{
      name: 'AND',
      summary: `如果所有参数都为真，AND函数返回布尔值true，否则返回布尔值 false
      用法：AND(逻辑表达式1,逻辑表达式2,...)
      示例：AND(语文成绩>90,数学成绩>90,英语成绩>90)，如果三门课成绩都> 90，返回true，否则返回false`
    }, {
      name: 'IF',
      summary: `IF函数判断一个条件能否满足；如果满足返回一个值，如果不满足则返回另外一个值
      用法：IF(逻辑表达式,为true时返回的值,为false时返回的值)
      示例：IF(语文成绩>60,"及格","不及格")，当语文成绩>60时返回及格，否则返回不及格。`
    }, {
      name: 'IFS',
      summary: `IFS函数检查是否满足一个或多个条件，且返回符合第一个TRUE条件的值，IFS可以取代多个嵌套IF语句。
      用法：IFS(逻辑表达式1,逻辑表达式1为true返回该值,逻辑表达式2,逻辑表达式2为true返回该值,...)
      示例：IFS(语文成绩>90,"优秀",语文成绩>80,"良好",语文成绩>=60,"及格",语文成绩<60,"不及格")，根据成绩返回对应的评价。`
    }, {
      name: 'SUMIF',
      summary: `示例：SUMIF([2,4,8,16], '>5') = 24
      摘要：返回指定范围的条件总和。`
    }, {
      name: 'SUMIFS',
      summary: `示例：SUMIFS([2,4,8,16], [1,2,3,4], '>=2', [1,2,4,8], '<=4') = 12
      摘要：根据多项条件返回范围之和。

      详解：第一个参数 [2,4,8,16] 为数据区域，之后每两个参数为一组，比如[1,2,3,4], '>=2' 和 [1,2,4,8], '<=4' 分成两组。
      第一组：在[1,2,3,4]中筛选出 >=2 的值所对应的下标，值为 "2,3,4"，所在下标为 1,2,3。
      第二组：在[1,2,4,8]中筛选出 <=4 的值所对应的下标，值为 "1,2,4" 所在下标为 0,1,2。
      最后根据两组结果的交集，下标为 1,2 所以，数据区域中下标为1和2的值分别为 4,8 相加得12
    `
    },
    ...LOGICAL
    ]
  },
  {
    name: '财务函数',
    children: [...FINANCIAL]
  },
  {
    name: '工程函数',
    children: [...ENGINEERING]
  },
  {
    name: '统计函数',
    children: [...STATISTICAL]
  }
];

/**
 * 以下定义 库@formulajs中 没有的函数
 */
function argsToArray(args) {
  const result = [];
  arrayEach(args, (value) => {
    result.push(value);
  });
  return result;
}
function arrayEach(array, iteratee) {
  let index = -1;
  const length = array.length;
  while (++index < length) {
    if (iteratee(array[index], index, array) === false) {
      break;
    }
  }
  return array;
}
function SUM() {
  let result = 0;
  arrayEach(argsToArray(arguments), (value) => {
    if (result instanceof Error) {
      return false;
    } else if (value instanceof Error) {
      result = value;
    } else if (typeof value === 'number') {
      result = math.add(result, value);
    } else if (typeof value === 'string') {
      const parsed = parseFloat(value);

      !isNaN(parsed) && (result = math.add(result, parsed));
    } else if (Array.isArray(value)) {
      const inner_result = SUM.apply(null, value);

      if (inner_result instanceof Error) {
        result = inner_result;
      } else {
        result = math.add(result, inner_result);
      }
    }
  });
  return result;
}
// 去重
function UNION() {
  try {
    const args = [...arguments];
    let res = [];
    args.forEach(i => {
      if (Array.isArray(i)) {
        res = res.concat(i);
      } else if (typeof i === 'string' || typeof i === 'number') {
        res.push(i);
      }
    });
    if (!res || res.length === 0) return '';
    return [...new Set(res)].join(',');
  } catch (error) {
    throw new Error(error);
  }
}
// 转为数值
function VALUE(arg) {
  if (!arg && arg !== 0) throw new Error('VALUE：参数错误');
  if (Array.isArray(arg)) arg = Number(arg);
  if (typeof arg === 'object' || isNaN(arg)) throw new Error('VALUE：参数错误');
  try {
    return Number(arg);
  } catch (error) {
    throw new Error(error);
  }
}
// 转为字符串
function TEXT(arg) {
  if (!arg && arg !== 0) throw new Error('VALUE：参数错误');
  if (Array.isArray(arg)) arg = arg.toString();
  if (typeof arg === 'object') throw new Error('TEXT：参数错误');
  try {
    return arg.toString();
  } catch (error) {
    throw new Error(error);
  }
}
// 转为大写金额
function RMBCAP(money) {
  if (!money && money !== 0) throw Error('RMBCAP：参数格式错误');
  if (Array.isArray(money)) money = Number(money);
  if (typeof money !== 'number' || isNaN(money)) throw Error('RMBCAP：参数格式错误');
  // 汉字的数字
  const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  // 基本单位
  const cnIntRadice = ['', '拾', '佰', '仟'];
  // 对应整数部分扩展单位
  const cnIntUnits = ['', '万', '亿', '兆'];
  // 对应小数部分单位
  const cnDecUnits = ['角', '分', '毫', '厘'];
  // 整数金额时后面跟的字符
  const cnInteger = '整';
  // 整型完以后的单位
  const cnIntLast = '元';
  // 最大处理的数字
  const maxNum = 999999999999999.9999;
  // 金额整数部分
  let integerNum;
  // 金额小数部分
  let decimalNum;
  // 输出的中文金额字符串
  let chineseStr = '';
  // 分离金额后用的数组，预定义
  let parts;
  if (money === '') { return ''; }
  money = parseFloat(money);
  if (money >= maxNum) {
    // 超出最大处理数字
    return '';
  }
  if (money === 0) {
    chineseStr = cnNums[0] + cnIntLast + cnInteger;
    return chineseStr;
  }
  // 转换为字符串
  money = money.toString();
  if (money.indexOf('.') === -1) {
    integerNum = money;
    decimalNum = '';
  } else {
    parts = money.split('.');
    integerNum = parts[0];
    decimalNum = parts[1].substr(0, 4);
  }
  // 获取整型部分转换
  if (parseInt(integerNum, 10) > 0) {
    let zeroCount = 0;
    const IntLen = integerNum.length;
    for (let i = 0; i < IntLen; i++) {
      const n = integerNum.substr(i, 1);
      const p = IntLen - i - 1;
      const q = p / 4;
      const m = p % 4;
      if (n === '0') {
        zeroCount++;
      } else {
        if (zeroCount > 0) {
          chineseStr += cnNums[0];
        }
        // 归零
        zeroCount = 0;
        chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
      }
      if (m === 0 && zeroCount < 4) {
        chineseStr += cnIntUnits[q];
      }
    }
    chineseStr += cnIntLast;
  }
  // 小数部分
  if (decimalNum !== '') {
    const decLen = decimalNum.length;
    for (let i = 0; i < decLen; i++) {
      const n = decimalNum.substr(i, 1);
      if (n !== '0') {
        chineseStr += cnNums[Number(n)] + cnDecUnits[i];
      }
    }
  }
  if (chineseStr === '') {
    chineseStr += cnNums[0] + cnIntLast + cnInteger;
  } else if (decimalNum === '') {
    chineseStr += cnInteger;
  }
  return chineseStr;
}
/**
 * 时间相关
 */
function parseDate(date) {
  if (!isNaN(date)) {
    if (date instanceof Date) {
      return new Date(date);
    }

    const d = parseFloat(date);

    return new Date(d);
  }

  if (typeof date === 'string') {
    date = new Date(date);

    if (!isNaN(date)) {
      return date;
    }
  }

  throw new Error('#VALUE!');
}
function DAYS(end_date, start_date) {
  end_date = parseDate(end_date);
  start_date = parseDate(start_date);
  return formulajs.DAYS(end_date, start_date);
}
// 将指定日期加/减指定天数
function DATEDELTA(date_text, days) {
  try {
    if (!date_text || (!days && days !== 0) || typeof days !== 'number') throw new Error('DATEDELTA：参数错误');
    const time = parseDate(date_text);
    const dayTime = days * 86400;
    const res = new Date((time.valueOf() / 1000 + dayTime) * 1000);
    return format(res, typeof date_text === 'number' || date_text.indexOf(':') >= 0 ? 'YYYY/MM/DD HH:mm:ss' : 'YYYY/MM/DD');
  } catch (error) {
    throw new Error(error);
  }
}

function DATEDIF(start_date, end_date, unit) {
  try {
    start_date = parseDate(start_date);
    end_date = parseDate(end_date);
    if (unit && (unit === 'h' || unit === 'm' || unit === 's')) {
      const startTime = Math.floor(start_date.valueOf() / 1000);
      const endTime = Math.floor(end_date.valueOf() / 1000);
      let result;
      switch (unit) {
        case 's':
          result = endTime - startTime;
          break;
        case 'm':
          result = Math.floor((endTime - startTime) / 60);
          break;
        case 'h':
          result = Number(((endTime - startTime) / (60 * 60)).toFixed(2));
          break;
      }
      return result;
    } else {
      return formulajs.DATEDIF(start_date, end_date, unit);
    }
  } catch (error) {
    return new Error('arguments error');
  }
}

function IFS() {
  for (let i = 0; i < arguments.length / 2; i++) {
    if (arguments[i * 2]) {
      return arguments[i * 2 + 1];
    }
  }

  return '';
}
export const diyFunction = {
  ...formulajs, SUM, DATEDIF, DAYS, IFS,
  RMBCAP, UNION, VALUE, TEXT, DATEDELTA
};
